using SmartCommunity.Models;
using Mapster;
using Microsoft.EntityFrameworkCore;

namespace SmartCommunity.WebApi.Services.System
{
    /// <summary>
    /// 服务类：菜单
    /// </summary>
    public class MenuService : BaseService<MenuEntity>
    {
        #region 构造函数
        protected readonly SCDBContext ctx;
        public MenuService(SCDBContext ctx)
        {
            this.ctx = ctx;
        }
        #endregion

        #region 数据查询 

        public async Task<List<MenuDto>> GetMenuTree(MenuQuery menuQuery, LoginUser user)
        {
            var tree = await ctx.Menus.Where(menuQuery.GetQueryExpression())
                .OrderBy(t => t.ParentId).ThenBy(t => t.SortNo)
                .ToListAsync();

            return tree.Where(a => a.Parent == null).Select(a => a.Adapt<MenuDto>()).ToList();
        }

        /// <summary>
        /// 根据菜单ID查询
        /// </summary>
        public async Task<MenuDto> FindMenuById(int menuId)
        {
            var entity = await FindById(menuId);
            return entity.Adapt<MenuDto>();
        }

        /// <summary>
        /// 根据ID查询实体类
        /// </summary>
        private async Task<MenuEntity> FindById(int id)
        {
            return await ctx.Menus.FindAsync(id) ?? throw new NotFoundException($"找不到指定的菜单,Id:{id}");
        }
        #endregion

        #region 增 删 改
        /// <summary>
        /// 新增菜单
        /// </summary>
        public async Task<MenuDto> CreateMenu(MenuDto dto, LoginUser user)
        {
            // 新建对象
            var entity = new MenuEntity();
            // 复制属性
            await CopyDtoToEntity(dto, entity, user, true);
            // 两次SaveChanges,需要在同一个事务里
            using var trans = await ctx.Database.BeginTransactionAsync();
            // 执行保存
            ctx.Menus.Add(entity);
            await ctx.SaveChangesAsync();

            await ctx.SaveChangesAsync();

            // 提交事务
            trans.Commit();
            // 返回Dto
            return entity.Adapt<MenuDto>();

        }

        private static MenuEntity CreateButton(MenuEntity menu, string name, string code, string icon, int sortNo)
        {
            return new MenuEntity()
            {
                ParentId = menu.MenuId,
                MenuType = MenuType.Button,
                MenuName = name,
                SortNo = sortNo,
                Icon = icon,
                Permission = menu.Permission + ":" + code,
                MenuPath = "",

                CreatedBy = menu.CreatedBy,
                UpdatedBy = menu.UpdatedBy,
                CreatedTime = menu.CreatedTime,
                UpdatedTime = menu.UpdatedTime,
            };
        }
        /// <summary>
        /// 更新菜单
        /// </summary>
        public async Task UpdateMenu(MenuDto dto, LoginUser user)
        {
            // 原始数据
            var entity = await FindById(dto.MenuId);
            // 更新字段
            await CopyDtoToEntity(dto, entity, user, false);
            // 执行更新
            await ctx.SaveChangesAsync();
        }

        /// <summary>
        /// 复制dto属性到实体字段
        /// </summary>
        private async Task CopyDtoToEntity(MenuDto dto, MenuEntity entity, LoginUser user, bool isNew)
        {
            // 检查数据重复
            if (await ctx.Menus.AnyAsync(a => a.MenuId != dto.MenuId && a.ParentId == dto.ParentId && a.MenuType == dto.MenuType && ((dto.MenuType != MenuType.Button && a.MenuPath == dto.MenuPath) || a.MenuName == dto.MenuName)))
            {
                throw new MessageException("当前层级已存在相同名称或路径的菜单");
            }
            entity.ParentId = dto.ParentId;
            entity.MenuName = dto.MenuName;
            entity.MenuType = dto.MenuType;
            entity.MenuPath = dto.MenuPath;
            entity.Permission = dto.Permission ?? "";
            entity.Icon = dto.Icon;
            entity.SortNo = dto.SortNo;
            entity.Remark = dto.Remark;

            // 记录操作人
            if (isNew)
            {
                entity.CreatedBy = user.Username;
                entity.CreatedTime = DateTime.Now;
            }
            entity.UpdatedBy = user.Username;
            entity.UpdatedTime = DateTime.Now;
        }

        /// <summary>
        /// 根据ID删除菜单
        /// </summary>
        public async Task DeleteByIds(IEnumerable<int> ids, LoginUser user)
        {
            var lstData = await ctx.Menus.Include(a => a.Children).Include(a => a.Roles).Where(a => ids.Contains(a.MenuId)).ToListAsync();
            if (lstData.Count != ids.Count())
            {
                throw new MessageException("查询出的数据和传入的ID不匹配，请刷新后再试。");
            }
            // 判断是否能删除
            foreach (var entity in lstData)
            {
                if (entity.Children.Count > 0)
                {
                    throw new MessageException("存在下级菜单，不允许删除");
                }
                // 清除和角色的对应关系
                entity.Roles.Clear();
                ctx.Menus.Remove(entity);
            }
            // 提交事务
            await ctx.SaveChangesAsync();
        }
        #endregion
    }
}
